import { DependencyContainer, InjectionToken } from 'tsyringe'
export interface ClassDecoratorHandler<O = any> {
    handle(container: DependencyContainer, options: O, target: any): void;
}
export type ClassMetadataKey<O> = InjectionToken<ClassDecoratorHandler<O>>
export function createClassDecorator<O>(metadataKey: ClassMetadataKey<O>) {
    return (container: DependencyContainer) => {
        return (options: O): ClassDecorator => {
            return (target: any) => {
                const handlers = container.resolveAll(metadataKey)
                handlers.map(handler => handler.handle(container, options, target))
            }
        }
    }
}

export interface PropertyDecoratorHandler<O = any> {
    handle(container: DependencyContainer, options: O, target: any, propertyKey: string | symbol): void;
}
export type PropertyMetadataKey<O> = InjectionToken<PropertyDecoratorHandler<O>>
export function createPropertyDecorator<O>(metadataKey: PropertyMetadataKey<O>) {
    return (container: DependencyContainer) => {
        return (options: O): PropertyDecorator => {
            return (target: any, propertyKey: string | symbol) => {
                const handlers = container.resolveAll(metadataKey)
                handlers.map(handler => handler.handle(container, options, target, propertyKey))
            }
        }
    }
}



export interface ParameterDecoratorHandler<O = any> {
    handle(container: DependencyContainer, options: O, target: any, propertyKey: string | symbol | undefined, index: number): void;
}
export type ParameterMetadataKey<O> = InjectionToken<ParameterDecoratorHandler<O>>
export function createParameterDecorator<O>(metadataKey: ParameterMetadataKey<O>) {
    return (container: DependencyContainer) => {
        return (options: O): ParameterDecorator => {
            return (target: any, propertyKey: string | symbol | undefined, index: number) => {
                const handlers = container.resolveAll(metadataKey)
                handlers.map(handler => handler.handle(container, options, target, propertyKey, index))
            }
        }
    }
}


export interface MethodDecoratorHandler<O = any> {
    handle(container: DependencyContainer, options: O, target: any, propertyKey: string | symbol | undefined, descriptor: TypedPropertyDescriptor<any>): void;
}
export type MethodMetadataKey<O> = InjectionToken<MethodDecoratorHandler<O>>
export function createMethodDecorator<O>(metadataKey: MethodMetadataKey<O>) {
    return (container: DependencyContainer) => {
        return (options: O): MethodDecorator => {
            return (target: any, propertyKey: string | symbol | undefined, descriptor) => {
                const handlers = container.resolveAll(metadataKey)
                handlers.map(handler => handler.handle(container, options, target, propertyKey, descriptor))
            }
        }
    }
}
